home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume25 / finger / part04 < prev    next >
Encoding:
Text File  |  1992-04-04  |  59.0 KB  |  2,353 lines

  1. Newsgroups: comp.sources.unix
  2. From: phil@Shiva.COM (Phil Budne)
  3. Subject: v25i167: finger - Phil's Finger Program, Part04/07
  4. Sender: unix-sources-moderator@pa.dec.com
  5. Approved: vixie@pa.dec.com
  6.  
  7. Submitted-By: phil@Shiva.COM (Phil Budne)
  8. Posting-Number: Volume 25, Issue 167
  9. Archive-Name: finger/part04
  10.  
  11. #! /bin/sh
  12. # This is a shell archive.  Remove anything before this line, then unpack
  13. # it by saving it into a file and typing "sh file".  To overwrite existing
  14. # files, type "sh file -c".  You can also feed this as standard input via
  15. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  16. # will see the following message at the end:
  17. #        "End of archive 4 (of 7)."
  18. # Contents:  conf.c names.c output.c select.c switch.c whois.c
  19. #   ymakefile
  20. # Wrapped by budd@bu-it on Fri Jul  6 13:22:03 1990
  21. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  22. if test -f conf.c -a "${1}" != "-c" ; then 
  23.   echo shar: Will not over-write existing file \"conf.c\"
  24. else
  25. echo shar: Extracting \"conf.c\" \(8973 characters\)
  26. sed "s/^X//" >conf.c <<'END_OF_conf.c'
  27. X/*
  28. X * conf.c -- read run time configuration file for finger
  29. X *
  30. X * Copyright (C) 1990  Philip L. Budne
  31. X *
  32. X * This file is part of "Phil's Finger Program".
  33. X *
  34. X * This program is free software; you can redistribute it and/or modify
  35. X * it under the terms of the GNU General Public License as published by
  36. X * the Free Software Foundation; either version 1, or (at your option)
  37. X * any later version.
  38. X *
  39. X */
  40. X
  41. X/* TODO:
  42. X * implement options and route
  43. X * do ttylocs from here? (nah, hardle needs them)
  44. X */
  45. X
  46. X/*
  47. X * The idea for formatting phone numbers comes from
  48. X * Michael Thompson <thompson@dalcs.UUCP> Dalhousie University,
  49. X * Halifax, NS in comp.bugs.4bsd on Sept 25, 1987 
  50. X * "BSD4.3 finger is Berkley dependent. +FIX" 
  51. X */
  52. X
  53. X# ifndef lint
  54. Xstatic char *rcsid = "$Id: conf.c,v 3.0 90/07/06 13:10:27 budd Rel $";
  55. X# endif /* lint not defined */
  56. X
  57. X# include <stdio.h>
  58. X# include <strings.h>
  59. X# include <ctype.h>
  60. X# include <pwd.h>
  61. X# include <grp.h>
  62. X# include "person.h"
  63. X# include "finger.h"
  64. X# include "args.h"            /* sw_debug */
  65. X
  66. X# define CONF "finger.conf"
  67. X# define NUMBER '#'
  68. X# define COMMENT '!'
  69. X
  70. XLOCAL int initialized = FALSE;
  71. XLOCAL char *confdirs[] = {
  72. X# ifdef CONFDIRS
  73. X    CONFDIRS,
  74. X# endif /* CONFDIRS defined */
  75. X    "/etc",
  76. X    "/usr/local/etc",
  77. X    "/usr/etc",
  78. X    ".",                /* for debugging.. move to first? */
  79. X    NULL
  80. X};
  81. X
  82. X# define NBUILDINGS 10            /* UGH! */
  83. XLOCAL struct building {
  84. X    char code;
  85. X    char *name;
  86. X} buildings[NBUILDINGS];
  87. XLOCAL int nbuildings = 0;
  88. X
  89. X# define NACCTS 32            /* UGH! */
  90. XLOCAL struct acct {
  91. X    unsigned short min, max;
  92. X    char group, *name;
  93. X} accts[NACCTS];
  94. XLOCAL int naccts = 0;
  95. X
  96. X# define NPHONES 32            /* UGH! */
  97. XLOCAL struct phone {
  98. X    int splats;
  99. X    char *pat;
  100. X} phones[NPHONES];
  101. XLOCAL int nphones = 0;
  102. X
  103. X# define NHIDDEN 32            /* UGH! */
  104. Xchar *hidden[NHIDDEN];
  105. XLOCAL int nhidden = 0;
  106. X
  107. X# define NPREFIX 32            /* UGH! */
  108. Xchar *prefix[NPREFIX];
  109. XLOCAL int nprefixes = 0;
  110. X
  111. XGLOBAL BOOL
  112. Xread_conf() {
  113. X    FILE *f;
  114. X    char **dp;
  115. X    char buf[ 512 ];
  116. X    enum { START, ACCT, BUILDING, HIDDEN, OPT, PHONE, PREFIX, ROUTE } state;
  117. X
  118. X    if( initialized )
  119. X    return( TRUE );
  120. X    initialized = TRUE;
  121. X
  122. X    /* read env variable for path(s)? */
  123. X
  124. X    for( dp = confdirs, f = NULL; f == NULL && *dp != NULL; dp++ ) {
  125. X    sprintf( buf, "%s/%s", *dp, CONF );
  126. X    f = fopen( buf, "r" );
  127. X    }
  128. X    if( f == NULL )
  129. X    return( FALSE );
  130. X
  131. X    if( sw_debug )
  132. X    printf("%s:\n", buf );
  133. X
  134. X    state = START;
  135. X    if( fgets( buf, sizeof( buf ), f ) == NULL ) {
  136. X    fclose( f );
  137. X    return( FALSE );
  138. X    }
  139. X
  140. X    do {                /* ...while fgets */
  141. X    char *cp;
  142. X
  143. X    switch( buf[0] ) {
  144. X    case '%':
  145. X        /* use perfect hashing? */
  146. X# define PAIR(a,b) (a)<<7|(b)
  147. X        switch( PAIR(buf[1],buf[2]) ) {
  148. X        case PAIR('a','c'):
  149. X        state = ACCT;
  150. X        break;
  151. X        case PAIR('b','u'):
  152. X        state = BUILDING;
  153. X        break;
  154. X        case PAIR('h','i'):
  155. X        state = HIDDEN;
  156. X        break;
  157. X        case PAIR('o','p'):
  158. X        state = OPT;
  159. X        break;
  160. X        case PAIR('p','h'):
  161. X        state = PHONE;
  162. X        break;
  163. X        case PAIR('p','r'):
  164. X        state = PREFIX;
  165. X        break;
  166. X        case PAIR('r','o'):
  167. X        state = ROUTE;
  168. X        break;
  169. X        default:
  170. X        state = START;
  171. X        break;
  172. X        }
  173. X        /* fall */
  174. X    case COMMENT:
  175. X        /* # is used in phones */
  176. X        continue;
  177. X    } /* switch on buf[0] */
  178. X
  179. X    cp = index( buf, '\n' );
  180. X    if( cp != NULL )
  181. X        *cp = EOS;
  182. X
  183. X    switch( state ) {
  184. X    case START:
  185. X        break;
  186. X
  187. X    case ACCT:
  188. X        if( naccts < NACCTS ) {
  189. X        char temp[ 128 ], *tp;    /* FIXME */
  190. X        BOOL lit, name, hyp;
  191. X        int min, max, grp;
  192. X        struct passwd *pw;
  193. X        struct group *gr;
  194. X
  195. X        name = FALSE;        /* no letters */
  196. X        lit = FALSE;        /* no litteral next */
  197. X        tp = temp;        /* output buffer */
  198. X        for( cp = buf; *cp; cp++ ) {
  199. X            if( *cp == '\\' ) {
  200. X            lit = name = TRUE; /* quote next, interpret as name */
  201. X            continue;
  202. X            }
  203. X            if( isspace(*cp) && !lit )
  204. X            break;
  205. X            if( !isdigit(*cp) )
  206. X            name = TRUE;
  207. X            *tp++ = *cp;
  208. X            lit = FALSE;
  209. X        }
  210. X        *tp = EOS;        /* tie off string */
  211. X        if( tp == temp || *cp == EOS ) /* empty string, or EOS? */
  212. X            break;        /* must have two fields */
  213. X
  214. X        hyp = (*cp == '-');    /* unquoted hypen means a range */
  215. X        if( !name )
  216. X            min = atoi( temp );
  217. X        else if( (gr = getgrnam( temp )) != NULL )
  218. X            min = gr->gr_gid;
  219. X        else if( (pw = getpwnam( temp )) != NULL )
  220. X            min = pw->pw_uid;
  221. X        else
  222. X            break;
  223. X
  224. X        if( hyp ) {
  225. X            tp = temp;
  226. X            name = lit = FALSE;
  227. X            for( ; *cp ; cp++ ) {
  228. X            if( *cp == '\\' ) {
  229. X                /* quote next, interpret as name */
  230. X                lit = name = TRUE;
  231. X                continue;
  232. X            }
  233. X            if( isspace(*cp) && !lit )
  234. X                break;
  235. X            if( !isdigit(*cp) )
  236. X                name = TRUE;
  237. X
  238. X            *tp++ = *cp;
  239. X            lit = FALSE;
  240. X            }
  241. X            if( tp == temp || *cp == EOS )
  242. X            break;
  243. X            *tp = EOS;
  244. X            if( !name )
  245. X            max = atoi( temp );
  246. X            else if( (gr = getgrnam( temp )) != NULL )
  247. X            max = gr->gr_gid;
  248. X            else if( (pw = getpwnam( temp )) != NULL )
  249. X            max = pw->pw_uid;
  250. X            else
  251. X            break;
  252. X        }
  253. X        else
  254. X            max = min;
  255. X
  256. X        if( !skipwhite(&cp) )
  257. X            break;
  258. X        grp = *cp++;
  259. X        skipwhite(&cp);
  260. X
  261. X        accts[naccts].min = min;
  262. X        accts[naccts].max = max;
  263. X        accts[naccts].group = grp;
  264. X        accts[naccts].name = savestr( cp );
  265. X        naccts++;
  266. X        if( sw_debug )
  267. X            printf("acct: %d-%d %c %s\n", min, max, grp, cp );
  268. X        }
  269. X        break;
  270. X
  271. X    case BUILDING:
  272. X        if( nbuildings < NBUILDINGS ) {
  273. X        cp = buf+1;
  274. X        if( skipwhite(&cp) ) {
  275. X            buildings[nbuildings].code = buf[0];
  276. X            buildings[nbuildings].name = savestr( cp );
  277. X            nbuildings++;
  278. X            if( sw_debug )
  279. X            printf("bldg: %c %s\n", buf[0], cp );
  280. X        }
  281. X        }
  282. X        break;
  283. X
  284. X    case OPT:
  285. X        /* options to set; ie; sw_berkeley, sw_its */
  286. X        break;
  287. X
  288. X    case PHONE:
  289. X        if( nphones < NPHONES ) {
  290. X        int splats;
  291. X
  292. X        splats = 0;
  293. X        for( cp = buf; *cp; cp++ )
  294. X            if( *cp == NUMBER )
  295. X            splats++;
  296. X        if( splats > 0 ) {
  297. X            phones[nphones].splats = splats;
  298. X            phones[nphones].pat = savestr( buf );
  299. X            nphones++;
  300. X            if( sw_debug )
  301. X            printf("phone: %d %s\n", splats, buf );
  302. X        }
  303. X        }
  304. X        break;
  305. X
  306. X    case HIDDEN:
  307. X        if( nhidden < NHIDDEN ) {
  308. X        hidden[nhidden] = savestr( buf );
  309. X        nhidden++;
  310. X        if( sw_debug )
  311. X            printf("hidden: %s\n", buf );
  312. X        }
  313. X        break;
  314. X
  315. X    case PREFIX:
  316. X        if( nprefixes < NPREFIX ) {
  317. X        prefix[nprefixes] = savestr( buf );
  318. X        nprefixes++;
  319. X        if( sw_debug )
  320. X            printf("prefix: %s\n", buf );
  321. X        }
  322. X        break;
  323. X
  324. X    case ROUTE:
  325. X        break;
  326. X
  327. X    } /* state switch */
  328. X    } while( fgets( buf, sizeof( buf ), f ) != NULL );
  329. X    if( sw_debug )
  330. X    printf("\
  331. Xconf: %d accts, %d buildings, %d hidden, %d phones, %d prefixes\n",
  332. X           naccts, nbuildings, nhidden, nphones, nprefixes );
  333. X    return( TRUE );
  334. X} /* read_conf */
  335. X
  336. X/*
  337. X *    routines called from outside...
  338. X */
  339. X
  340. XGLOBAL int ishidden( str )
  341. X    char *str;
  342. X{
  343. X    register int i;
  344. X
  345. X    for( i = 0; i < nhidden; i++ )
  346. X    if( strcmp( str, hidden[i] ) == 0 )
  347. X        return( TRUE );
  348. X    return( FALSE );
  349. X}
  350. X
  351. XGLOBAL char *conf_prefix( i )
  352. X    int i;
  353. X{
  354. X    if( i > nprefixes )
  355. X    return( NULL );
  356. X    return( prefix[i] );
  357. X}
  358. X
  359. XGLOBAL void acct_group( pp )
  360. X    PERSON *pp;
  361. X{
  362. X    int i;
  363. X    register struct acct *ap;
  364. X
  365. X    for( i = 0, ap = accts; i < naccts; i++, ap++ ) {
  366. X    if( ap->min <= ap->max ) {
  367. X        if( pp->p_gid >= ap->min && pp->p_gid <= ap->max ) {
  368. X        pp->p_group = ap->group;
  369. X        return;
  370. X        }
  371. X    }
  372. X    else if( pp->p_gid >= ap->max && pp->p_gid <= ap->min ) {
  373. X        pp->p_group = ap->group;
  374. X        return;
  375. X    }
  376. X    }
  377. X    if( pp->p_gid == pp->p_uid )
  378. X    pp->p_group = '.';        /* use '=' ? */
  379. X    else
  380. X    pp->p_group = ' ';
  381. X}
  382. X
  383. XGLOBAL char *acct_name( pp )
  384. X    PERSON *pp;
  385. X{
  386. X    int i;
  387. X    register struct acct *ap;
  388. X
  389. X    for( i = 0, ap = accts; i < naccts; i++, ap++ ) {
  390. X    if( ap->min <= ap->max ) {
  391. X        if( pp->p_gid >= ap->min && pp->p_gid <= ap->max )
  392. X        return( ap->name );
  393. X    }
  394. X    else if( pp->p_gid >= ap->max && pp->p_gid <= ap->min )
  395. X        return( ap->name );
  396. X    }
  397. X    return( NULL );
  398. X}
  399. X
  400. XGLOBAL void catphone( dest, phone )
  401. X    register char *dest, *phone;
  402. X{
  403. X    char *ph;
  404. X    int digits, other, i;
  405. X
  406. X    ph = phone;
  407. X    for( digits = other = 0; *phone != EOS; phone++ )
  408. X    if( isdigit(*phone) )
  409. X        digits++;
  410. X    else
  411. X        other++;
  412. X
  413. X    if( 
  414. X# ifdef FORMAT_DIGITS_ONLY
  415. X       other == 0 &&
  416. X# endif /* FORMAT_DIGITS_ONLY defined */
  417. X       digits > 0 ) {
  418. X    while( *dest != EOS )
  419. X        dest++;
  420. X
  421. X    for( i = 0; i < nphones; i++ )
  422. X        if( phones[i].splats == digits ) {
  423. X        register char *pat;
  424. X
  425. X        phone = ph;
  426. X        for( pat = phones[i].pat; *pat != EOS; pat++ ) {
  427. X            if( *pat == NUMBER ) {
  428. X            while( !isdigit(*phone) )
  429. X                phone++;
  430. X            *dest++ = *phone++;
  431. X            }
  432. X            else
  433. X            *dest++ = *pat;
  434. X        }
  435. X        *dest = EOS;
  436. X        return;
  437. X        }
  438. X    } /* other == 0 && digits > 0 */
  439. X    strcat( dest, phone );
  440. X}
  441. X
  442. X/* given an office string, return formatted in a static buffer */
  443. X# define OFFSIZ 100
  444. X
  445. XGLOBAL char *office( s )
  446. X    char *s;
  447. X{
  448. X    char offbuff[OFFSIZ];
  449. X    int i, l;
  450. X
  451. X    l = strlen( s );
  452. X    if( l > OFFSIZ - 10 )    /* close? */
  453. X    return( s );        /* good-bye */
  454. X
  455. X    for( i = 0; i < nbuildings; i++ )
  456. X    if( buildings[i].code == s[l-1] )
  457. X        break;
  458. X
  459. X    if( i >= nbuildings )
  460. X    return( s );
  461. X
  462. X    strcpy(offbuff, s);
  463. X    offbuff[l-1] = EOS;
  464. X    strcat(offbuff, buildings[i].name );
  465. X    return( offbuff );
  466. X} /* office */
  467. END_OF_conf.c
  468. if test 8973 -ne `wc -c <conf.c`; then
  469.     echo shar: \"conf.c\" unpacked with wrong size!
  470. fi
  471. # end of overwriting check
  472. fi
  473. if test -f names.c -a "${1}" != "-c" ; then 
  474.   echo shar: Will not over-write existing file \"names.c\"
  475. else
  476. echo shar: Extracting \"names.c\" \(7736 characters\)
  477. sed "s/^X//" >names.c <<'END_OF_names.c'
  478. X/*
  479. X * names.c -- lookup names via nlist
  480. X *
  481. X * Copyright (C) 1986, 1990  Philip L. Budne
  482. X *
  483. X * This file is part of "Phil's Finger Program".
  484. X *
  485. X * This program is free software; you can redistribute it and/or modify
  486. X * it under the terms of the GNU General Public License as published by
  487. X * the Free Software Foundation; either version 1, or (at your option)
  488. X * any later version.
  489. X *
  490. X */
  491. X
  492. X# ifndef lint
  493. Xstatic char *rcsid = "$Id: names.c,v 3.0 90/07/06 13:11:24 budd Rel $";
  494. X# endif /* lint not defined */
  495. X
  496. X# include "finger.h"
  497. X
  498. X# ifdef DEBUGSW
  499. X# define IFDEBUG( x ) if( sw_debug ) printf x
  500. X# else  /* DEBUGSW not defined */
  501. X# define IFDEBUG( x )
  502. X# endif /* DEBUGSW not defined */
  503. X
  504. X# if Umax != 42                /* the rest of the file.... */
  505. X
  506. X# ifdef USG
  507. X# include <fcntl.h>
  508. X/* TODO: <sys/var.h> check info_proc vs. ((proc *)v.ve_proc) - v.v_proc */
  509. X# else  /* USG not defined */
  510. X# include <sys/file.h>
  511. X# endif /* USG not defined */
  512. X# include <sys/types.h>
  513. X# include <sys/stat.h>
  514. X# ifdef AUX
  515. X# include <a.out.h>
  516. X# else  /* AUX not defined */
  517. X# include <nlist.h>
  518. X# endif /* AUX not defined */
  519. X# include <stdio.h>
  520. X
  521. X# include "args.h"
  522. X# include "info.h"            /* after finger.h */
  523. X# include "kmem.h"
  524. X
  525. Xlong symdate =
  526. X# include "symdate.h"
  527. X;
  528. X
  529. XGLOBAL struct info I;
  530. X
  531. Xextern FTYPE kmem;            /* from kmem.c */
  532. X
  533. Xextern char longversion[];        /* from version.c */
  534. Xextern char *sys_errlist[];        /* from library */
  535. Xextern int errno;            /* from library */
  536. X
  537. Xstruct nlist nl[] = {            /* nlist table */
  538. X# ifdef UNDERSCORE_NLIST_NAMES
  539. X# define SYM(s,sc,m) { s },
  540. X# else  /* UNDERSCORE_NLIST_NAMES not defined */
  541. X# define SYM(s,sc,m) { sc },
  542. X# endif /* UNDERSCORE_NLIST_NAMES not defined */
  543. X# include "syms.h"
  544. X# undef SYM
  545. X    ""
  546. X};
  547. X# define LNL ((sizeof(nl)/sizeof(struct nlist))-1)
  548. X
  549. Xunsigned long *nvptrs[] = {
  550. X# define SYM(s,sc,m) CONC(&I.info_,m) ,    /* build table of pointers to values */
  551. X# include "syms.h"
  552. X# undef SYM
  553. X};
  554. X
  555. XLOCAL int readnlist(kfile)        /* force read of nlist */
  556. Xchar *kfile;
  557. X{
  558. X    register int i;
  559. X    struct stat kernst;
  560. X# ifdef HAVE_VERSION
  561. X    char kmem_verstr[ VERSTRLEN+1 ];
  562. X# endif /* HAVE_VERSION defined */
  563. X
  564. X    IFDEBUG(("getting namelist from %s\n", kfile ));
  565. X
  566. X    if( nlist(kfile, nl) < 0 ) {
  567. X    fprintf(stderr, "%%Could not read %s namelist\n", kfile );
  568. X    return( FALSE );
  569. X    }
  570. X
  571. X    for( i = 0; i < LNL; i++ ) {
  572. X    if(
  573. X# ifndef COFF
  574. X      nl[i].n_type == N_UNDF &&
  575. X# endif /* COFF not defined */
  576. X      nl[i].n_value == 0L ) {
  577. X        fprintf(stderr, "%%No namelist entry for %s\n", nl[i].n_name );
  578. X        return( FALSE );
  579. X    } /* empty entry */
  580. X    *nvptrs[i] = nl[i].n_value;
  581. X    } /* for i */
  582. X
  583. X    if( stat( kfile, &kernst ) == 0 ) {
  584. X    I.info_kerneldate = kernst.st_mtime;
  585. X    I.info_kernelsize = kernst.st_size;
  586. X    I.info_symdate = symdate;
  587. X    } /* stat */
  588. X
  589. X    strncpy( I.info_fingerversion, longversion, sizeof( I.info_fingerversion));
  590. X# ifdef HAVE_VERSION
  591. X    bzero( I.info_verstr, sizeof( I.info_verstr ) );
  592. X    bzero( kmem_verstr,  sizeof( kmem_verstr )  );
  593. X
  594. X    /* save _version from /vmunix in I.info_verstr */
  595. X    if( read_vmunix( KERNEL_FILE, I.info_version,
  596. X            I.info_verstr, VERSTRLEN ) ) {
  597. X    I.info_verstr[VERSTRLEN] = '\0';
  598. X
  599. X# ifdef DEBUGSW
  600. X    if( sw_debug ) {
  601. X        printf("info_version %#x\n", I.info_version );
  602. X        printf("%s:\n", kfile );
  603. X        printf("%*s\n", -VERSTRLEN, I.info_verstr );
  604. X    }
  605. X# endif /* DEBUGSW defined */
  606. X
  607. X# ifdef PICKY
  608. X    /*
  609. X     * be picky.... insist that running kernel
  610. X     * contain same string at same location
  611. X     */
  612. X
  613. X    if( KMEMREAD(I.info_version, kmem_verstr,  VERSTRLEN ) ) {
  614. X        kmem_verstr[VERSTRLEN] = '\0';
  615. X
  616. X# ifdef DEBUGSW
  617. X        if( sw_debug ) {
  618. X        printf("kmem @ %#x:\n", I.info_version );
  619. X        printf("%*s\n", -VERSTRLEN, kmem_verstr );
  620. X        }
  621. X# endif /* DEBUGSW defined */
  622. X
  623. X        /* if match, we win */
  624. X        if( strncmp( kmem_verstr, I.info_verstr, VERSTRLEN ) == 0 )
  625. X        return( TRUE );
  626. X    } /* kread ok */
  627. X# endif /* PICKY defined */
  628. X    } /* got version from /vmunix file */
  629. X# ifdef PICKY
  630. X    return( FALSE );
  631. X# else  /* PICKY not defined */
  632. X    return( TRUE );
  633. X# endif /* PICKY not defined */
  634. X# else  /* HAVE_VERSION not defined */
  635. X    return( TRUE );
  636. X# endif /* HAVE_VERSION not defined */
  637. X} /* readnlist */
  638. X
  639. XLOCAL int writenfile( kfile )
  640. Xchar *kfile;
  641. X{
  642. X    int nfile;
  643. X
  644. X    if( !readnlist( kfile ) )
  645. X    return( FALSE );
  646. X
  647. X    if( sw_nosave )            /* write prohibited? */
  648. X    return( TRUE );            /* be nice */
  649. X
  650. X    IFDEBUG(("writing %s\n", SAVED_NLIST ));
  651. X    if( (nfile=open( SAVED_NLIST, O_TRUNC|O_CREAT|O_WRONLY,
  652. X            NLIST_MODE)) >= 0 ) {
  653. X    write( nfile, &I, sizeof( I ) );
  654. X# ifndef USG
  655. X    fchown( nfile, geteuid(), getegid() );
  656. X    fchmod( nfile, NLIST_MODE );
  657. X# else  /* USG defined */
  658. X    chown( SAVED_NLIST, geteuid(), getegid() );
  659. X    chmod( SAVED_NLIST, NLIST_MODE );
  660. X# endif /* USG defined */
  661. X    close( nfile );
  662. X    } /* open for write */
  663. X    else
  664. X    fprintf( stderr, "%%Could not write %s (%s)\n",
  665. X        SAVED_NLIST, sys_errlist[ errno ] );
  666. X    return( TRUE );
  667. X} /* writenfile */
  668. X
  669. XGLOBAL int readnames() {    /* get nlist from save file or /vmunix */
  670. X# ifdef SAVED_NLIST
  671. X    int nfile, oknfile, oknlist;
  672. X    struct stat savst, kernst;
  673. X    char kmem_verstr[ VERSTRLEN+1 ];
  674. X
  675. X    oknfile = oknlist = FALSE;
  676. X
  677. X    /* check if SAVED_NLIST exists, is right size */
  678. X    /* built from same copy of syms.h */
  679. X    if( !sw_read ) {                /* not getting new save */
  680. X    IFDEBUG(("%s: ", SAVED_NLIST ));
  681. X    if( stat( SAVED_NLIST, &savst ) == 0 &&    /* got status of save file */
  682. X       savst.st_size == sizeof( I ) ) {    /* data file is right size */
  683. X        IFDEBUG(("size ok "));
  684. X
  685. X        if( (nfile = open( SAVED_NLIST, O_RDONLY )) >= 0 ) { /* opened */
  686. X        if( read( nfile, &I, sizeof( I ) ) == sizeof( I ) ) {
  687. X            IFDEBUG(("read ok "));
  688. X            if( I.info_symdate == symdate ) {/* same copy of syms.h? */
  689. X            oknfile = TRUE;        /* doing fine */
  690. X            IFDEBUG(("symdate ok "));
  691. X            } /* same copy of syms.h */
  692. X# ifdef DEBUGSW
  693. X            else if( sw_debug )
  694. X            printf("*symdate mismatch*");
  695. X# endif /* DEBUGSW defined */
  696. X
  697. X        }
  698. X        close( nfile );
  699. X        } /* open ok */
  700. X    } /* stat + size ok */
  701. X    IFDEBUG(("\n"));
  702. X    } /* not sw_read */
  703. X
  704. X    if( sw_read || !oknfile )        /* if no good fall back on /vmunix */
  705. X    return( writenfile( KERNEL_FILE ) );
  706. X
  707. X# ifdef AUTONLIST
  708. X    /*
  709. X     *    does version string in running kernel match that of
  710. X     *  the kernel that was running when the nlist file was created?
  711. X     */
  712. X# ifdef HAVE_VERSION
  713. X    if( I.info_version != 0L ) {        /* have addr for verstr */
  714. X    bzero( kmem_verstr, sizeof( kmem_verstr ) );
  715. X    if( KMEMREAD( I.info_version, kmem_verstr, VERSTRLEN ) ) {
  716. X# ifdef DEBUGSW
  717. X        if( sw_debug ) {
  718. X        printf("kmem @ %#x:\n", I.info_version );
  719. X        printf("%*s\n", -VERSTRLEN, kmem_verstr );
  720. X        printf("info_verstr:\n");
  721. X        printf("%*s\n", -VERSTRLEN, I.info_verstr );
  722. X        } /* sw_debug */
  723. X# endif /* DEBUGSW defined */
  724. X        if( strncmp( I.info_verstr, kmem_verstr, VERSTRLEN ) == 0  )
  725. X        oknlist = TRUE;            /* matches!! */
  726. X    } /* kread ok */
  727. X    } /* version != 0 */
  728. X    else
  729. X# endif /* HAVE_VERSION defined */
  730. X    if( stat( KERNEL_FILE, &kernst ) == 0 &&   /* get kernel date/size */
  731. X        savst.st_mtime > kernst.st_mtime &&      /* more recent than kernel */
  732. X        I.info_kerneldate == kernst.st_mtime && /* same /vmunix */
  733. X        I.info_kernelsize == kernst.st_size ) {
  734. X# ifdef DEBUGSW
  735. X    if( sw_debug )
  736. X        printf("%s and %s kernel size and date match\n",
  737. X           SAVED_NLIST, KERNEL_FILE );
  738. X# endif /* DEBUGSW defined */
  739. X    oknlist = TRUE;
  740. X    } /* stat ok... */
  741. X    if( !oknlist )
  742. X    return( writenfile( KERNEL_FILE ) );
  743. X# else  /* AUTONLIST not defined */
  744. X    if( !oknlist )
  745. X    return( readnlist( KERNEL_FILE ) );
  746. X# endif /* AUTONLIST not defined */
  747. X    return( TRUE );
  748. X# else  /* SAVED_NLIST not defined */
  749. X    return( readnlist( KERNEL_FILE ) );
  750. X# endif /* SAVED_NLIST not defined */
  751. X} /* readnames */
  752. X
  753. X# endif /* Umax != 42 */
  754. X
  755. X/*
  756. X * Local variables:
  757. X * comment-column: 40
  758. X * End:
  759. X */
  760. END_OF_names.c
  761. if test 7736 -ne `wc -c <names.c`; then
  762.     echo shar: \"names.c\" unpacked with wrong size!
  763. fi
  764. # end of overwriting check
  765. fi
  766. if test -f output.c -a "${1}" != "-c" ; then 
  767.   echo shar: Will not over-write existing file \"output.c\"
  768. else
  769. echo shar: Extracting \"output.c\" \(7837 characters\)
  770. sed "s/^X//" >output.c <<'END_OF_output.c'
  771. X/*
  772. X * output.c -- terminal & output for new finger
  773. X *
  774. X * Copyright (C) 1986, 1990  Philip L. Budne
  775. X *
  776. X * This file is part of "Phil's Finger Program".
  777. X *
  778. X * This program is free software; you can redistribute it and/or modify
  779. X * it under the terms of the GNU General Public License as published by
  780. X * the Free Software Foundation; either version 1, or (at your option)
  781. X * any later version.
  782. X *
  783. X */
  784. X
  785. X# ifndef lint
  786. Xstatic char *rcsid = "$Id: output.c,v 3.0 90/07/06 13:11:28 budd Rel $";
  787. X# endif /* lint not defined */
  788. X
  789. X# include "finger.h"
  790. X# include <sys/types.h>
  791. X# include <sys/ioctl.h>
  792. X# include <sys/stat.h>
  793. X# include <stdio.h>
  794. X# ifdef TTY_GROUP
  795. X# include <grp.h>
  796. X# endif /* TTY_GROUP defined */
  797. X# include "output.h"
  798. X# include "args.h"            /* sw_output (before luser.h) */
  799. X# include "luser.h"
  800. X
  801. Xextern char *getenv();            /* from library */
  802. Xextern int netfinger;            /* from args.c */
  803. X
  804. XLOCAL int term_width;            /* termcap width */
  805. XLOCAL int output_col;            /* keep track of chars outchar'ed */
  806. XLOCAL int done_output;            /* keep track for blank lines */
  807. X
  808. X# ifndef DEFWIDTH
  809. X# define DEFWIDTH (MAXLINE-1)
  810. X# endif /* DEFWIDTH not defined */
  811. X
  812. XGLOBAL void ptree( u, routine )
  813. Xregister LUSER *u;
  814. Xint (*routine)();
  815. X{
  816. X    if( u == NULL )
  817. X        return;
  818. X
  819. X    if( u->u_left != NULL )
  820. X        ptree( u->u_left, routine );
  821. X
  822. X    (*routine)(u);
  823. X
  824. X    if( u->u_right != NULL )
  825. X        ptree( u->u_right, routine );
  826. X} /* ptree */
  827. X
  828. XGLOBAL char *intstr(s, sex)        /* print an interval */
  829. Xchar *s;                /* buffer to use (if needed) */
  830. Xlong sex;
  831. X{
  832. X    long min, hours, days;
  833. X
  834. X    min = sex / 60;            /* get minutes */
  835. X
  836. X    s[0] = EOS;                /* zap buffer */
  837. X    if( min <= 0 )            /* worth thinking about? */
  838. X    return( s );
  839. X
  840. X    hours = min / 60;            /* get hours */
  841. X    min = min % 60;            /* cast out hours */
  842. X
  843. X    days = hours / 24;            /* get number of days */
  844. X    hours = hours % 24;            /* cast out days */
  845. X
  846. X    if( days > 0 ) {            /* over a day? */
  847. X        if( days < 10 ) {        /* but still 1 digit? */
  848. X        if( hours < 1 )
  849. X        sprintf(s, "%dday", days); /* don't print 0h */
  850. X        else if( hours < 10 )
  851. X        sprintf(s, "%dd%dh", days, hours ); /* <days>d<hours>h */
  852. X        else
  853. X        sprintf(s, "%dd%d", days, hours ); /* <days>d<hours> */
  854. X    } /* < 10 days */
  855. X    else {
  856. X        int weeks, d2;
  857. X
  858. X        weeks = days / 7;
  859. X        d2 = days % 7;
  860. X        if( weeks < 10 ) {
  861. X        if( d2 == 0 ) {
  862. X            if( hours < 10 )
  863. X            sprintf(s, "%dw%dh", weeks, hours );
  864. X            else
  865. X            sprintf(s, "%dwks", weeks );
  866. X        }
  867. X        else
  868. X            sprintf(s, "%dw%dd", weeks, d2 );
  869. X        } /* < 10 weeks */
  870. X        else if( weeks < 100 ) {     /* (693 days!) */
  871. X        if( d2 > 0 )
  872. X            sprintf(s, "%dw%d", weeks, d2 );
  873. X        else
  874. X            sprintf(s, "%dwk", weeks );
  875. X        } /* lt 100 weeks */
  876. X        else if( days < 1000 )
  877. X        sprintf(s, "%3dd", days); /* print three digits of day */
  878. X        else            /* print years?? .... nah... */
  879. X        strcpy(s, "*:**");    /* P-U-N-T ! */
  880. X    } /* > 9 days */
  881. X    } /* days > 0 */
  882. X    else {                /* days == 0 */
  883. X    if( hours == 0 )        /* less than an hour? */
  884. X        sprintf(s, "%4d", min);     /* just minutes */
  885. X    else if( hours < 10 )        /* one digit of hours? */
  886. X        sprintf(s, "%1d:%02d", hours, min);    /* print h:mn */
  887. X    else                /* hours >= 10 (must be <= 23) */
  888. X        sprintf(s, "%2d:%1d", hours, min / 10); /* print hh:m */
  889. X    } /* days == 0 */
  890. X    return( s );      
  891. X} /* intstr */
  892. X
  893. X/*
  894. X *    termstat - given a LUSER record, get stat(2) information for terminal
  895. X *           returns TRUE for success
  896. X */
  897. X
  898. XGLOBAL void termstat( u )
  899. XLUSER *u;
  900. X{
  901. X    char term[30];
  902. X    struct stat stb;
  903. X# ifdef Umax
  904. X    LOCAL short rdpminor = -1;
  905. X# endif /* Umax defined */
  906. X
  907. X# ifdef TTY_GROUP
  908. X    LOCAL int ttygroup = -1;
  909. X
  910. X    if( ttygroup < 0 ) {
  911. X    struct group *gr;
  912. X    if( (gr = getgrnam("tty")) != NULL )
  913. X        ttygroup = gr->gr_gid;
  914. X# ifdef TTY_GROUP_NUMBER
  915. X    else
  916. X        ttygroup = TTY_GROUP_NUMBER;
  917. X# endif /* TTY_GROUP_NUMBER defined */
  918. X    endgrent();
  919. X    } /* get ttygroup */
  920. X# endif /* TTY_GROUP defined */
  921. X
  922. X    if( u == NULL )
  923. X    return;
  924. X
  925. X# ifdef Umax
  926. X    if( rdpminor == -1 ) {
  927. X    if( stat( "/dev/rdpcontrol", &stb ) == 0 && 
  928. X       (stb.st_mode & S_IFMT) == S_IFCHR )
  929. X        rdpminor = minor( stb.st_rdev );
  930. X    else
  931. X        rdpminor = -2;
  932. X    }
  933. X# endif /* Umax defined */
  934. X
  935. X    strcpy(term, "/dev/");
  936. X    strcat(term, u->u_line);
  937. X    if( stat(term, &stb) < 0 || (stb.st_mode & S_IFMT) != S_IFCHR ) {
  938. X    u->u_flags |= U_BADTTY;        /* bad device!? */
  939. X    return;
  940. X    }
  941. X
  942. X    if( sw_output )
  943. X    u->u_idle = time( 0 ) - stb.st_mtime; /* save (output) idle time */
  944. X    else
  945. X    u->u_idle = time( 0 ) - stb.st_atime; /* save idle time */
  946. X
  947. X    u->u_ttydev = stb.st_rdev;        /* save major/minor device numbers */
  948. X# ifdef AIX3
  949. X    if( S_ISMPX( stb.st_mode ) ) {
  950. X    char *cp;
  951. X
  952. X    cp = rindex( u->u_line, '/' );
  953. X    if( cp != NULL )
  954. X        u->u_ttydev += atoi( cp+1 );
  955. X    }
  956. X# endif /* AIX3 defined */
  957. X
  958. X# ifdef Umax
  959. X    if( minor(stb.st_rdev) == rdpminor ) {
  960. X    u->u_ttyaddr = stb.st_rdaddr;     /* annex/rdp inet addr */
  961. X    u->u_ttytype = stb.st_rdtype;    /* annex/rdp device type */
  962. X    u->u_ttynum =  stb.st_rdnum;    /* annex/rdp line number */
  963. X    }
  964. X    else
  965. X    u->u_ttyaddr = 0;        /* needed in Umax 4.3 (rel 4.0) */
  966. X# endif /* Umax defined */
  967. X
  968. X    if( (stb.st_mode & 0100) != 0 )    /* owner execute? */
  969. X    u->u_flags |= U_BIFF;        /* yes, biff y */
  970. X
  971. X    if( (stb.st_mode & 01) != 0 )    /* world execute? */
  972. X    u->u_flags |= U_HUNGRY;        /* yes, is hungry! */
  973. X
  974. X# ifdef TTY_GROUP
  975. X    if( (stb.st_mode & 0002) == 0 && 
  976. X       (stb.st_gid != ttygroup || (stb.st_mode & 0020) == 0 ) )
  977. X    u->u_flags |= U_NOWRITE;    /* no, msg n */
  978. X# else  /* TTY_GROUP not defined */
  979. X    if( (stb.st_mode & 0002) == 0 )    /* world write permission? */
  980. X    u->u_flags |= U_NOWRITE;    /* no, msg n */
  981. X# endif /* TTY_GROUP not defined */
  982. X    
  983. X    return;
  984. X} /* termstat */
  985. X
  986. XGLOBAL char *gtname( s )
  987. Xchar *s;
  988. X{
  989. X    /* .see TTY_PREFIX (in getent.c) */
  990. X    if( *s == 't' && s[1] == 't' && s[2] == 'y' )
  991. X    return( s+3 );
  992. X# ifdef UmaxV
  993. X    if( *s == 'r' && s[1] == 't' || *s == 'R' && s[1] == 'T' )
  994. X    return( s+2 );
  995. X# endif /* UmaxV defined */
  996. X    return( s );
  997. X} /* gtname */
  998. X
  999. X/*
  1000. X *    outline - output a line of text, obeying width of device
  1001. X */
  1002. X
  1003. XGLOBAL void outchar(c)
  1004. Xchar c;
  1005. X{
  1006. X    if( c == '\t' )
  1007. X    output_col = (output_col + 8) & ~7;
  1008. X    else if( c == '\n' ) {
  1009. X    output_col = 0;
  1010. X    if( netfinger )
  1011. X        putc('\r', OUTPUT );
  1012. X    }
  1013. X    else
  1014. X    output_col++;
  1015. X    done_output = TRUE;
  1016. X    putc(c, OUTPUT);
  1017. X} /* outchar */
  1018. X
  1019. XGLOBAL void outline( line )
  1020. Xregister char *line;
  1021. X{
  1022. X    register int c;
  1023. X
  1024. X    while( output_col < term_width ) {
  1025. X    if( (c = *line++) == EOS )
  1026. X        break;
  1027. X    else
  1028. X        outchar(c);
  1029. X    } /* for col */
  1030. X
  1031. X    outchar('\n');
  1032. X} /* outline */
  1033. X
  1034. XGLOBAL void blankline() {
  1035. X    if( done_output )
  1036. X    outchar( '\n' );
  1037. X    done_output = FALSE;
  1038. X} /* blankline */
  1039. X
  1040. XGLOBAL void getterm() {
  1041. X# ifdef TIOCGWINSZ            /* 4.3 */
  1042. X    struct winsize ws;
  1043. X# endif /* TIOCGWINSZ defined */
  1044. X# ifdef TIOCGSIZE            /* SOS3 */
  1045. X    struct ttysize ts;
  1046. X# endif /* TIOCGSIZE defined */
  1047. X    char tbuf[1024];            /* termcap defn */
  1048. X    char *term;                /* terminal type */
  1049. X    int w;                /* width */
  1050. X
  1051. X    if( netfinger || !isatty(STD_OUTPUT) ) { /* stdout not a terminal? */
  1052. X    term_width = PLUS_INF;        /* no output truncation */
  1053. X    return;
  1054. X    }
  1055. X    term_width = DEFWIDTH;
  1056. X    w = -1;
  1057. X
  1058. X# ifdef TIOCGWINSZ            /* 4.3 ioctl */
  1059. X    if( ioctl( STD_OUTPUT, TIOCGWINSZ, &ws ) == 0 )
  1060. X    w = ws.ws_col;
  1061. X# endif /* TIOCGWINSZ defined */
  1062. X# ifdef TIOCGSIZE
  1063. X    if( w <= 0 && ioctl( STD_OUTPUT, TIOCGSIZE, &ts ) == 0 )
  1064. X    w = ts.ts_cols;
  1065. X# endif /* TIOCGSIZE defined */
  1066. X    if( (term = getenv("TERM")) != NULL && /* get terminal type */
  1067. X       tgetent(tbuf, term) == 1 ) {    /* get termcap entry into tbuf */
  1068. X    if( w <= 0 )
  1069. X        w = tgetnum("co");        /* get cols */
  1070. X
  1071. X    if( tgetflag("am") )        /* auto wrap? */
  1072. X        w--;            /* yes, narrow by 1 */
  1073. X    } /* got termcap entry */
  1074. X    else
  1075. X    w--;                /* assume the worst */
  1076. X
  1077. X    if( w > 0 )                /* get width? */
  1078. X    term_width = w;            /* set it */
  1079. X} /* getterm */
  1080. X
  1081. X/*
  1082. X * Local variables:
  1083. X * comment-column: 40
  1084. X * End:
  1085. X */
  1086. END_OF_output.c
  1087. if test 7837 -ne `wc -c <output.c`; then
  1088.     echo shar: \"output.c\" unpacked with wrong size!
  1089. fi
  1090. # end of overwriting check
  1091. fi
  1092. if test -f select.c -a "${1}" != "-c" ; then 
  1093.   echo shar: Will not over-write existing file \"select.c\"
  1094. else
  1095. echo shar: Extracting \"select.c\" \(7584 characters\)
  1096. sed "s/^X//" >select.c <<'END_OF_select.c'
  1097. X/*
  1098. X * select.c -- perform selection process for finger
  1099. X *
  1100. X * Copyright (C) 1986, 1990  Philip L. Budne
  1101. X *
  1102. X * This file is part of "Phil's Finger Program".
  1103. X *
  1104. X * This program is free software; you can redistribute it and/or modify
  1105. X * it under the terms of the GNU General Public License as published by
  1106. X * the Free Software Foundation; either version 1, or (at your option)
  1107. X * any later version.
  1108. X *
  1109. X */
  1110. X
  1111. X# ifndef lint
  1112. Xstatic char *rcsid = "$Id: select.c,v 3.0 90/07/06 13:11:41 budd Rel $";
  1113. X# endif /* lint not defined */
  1114. X
  1115. X# include <pwd.h>
  1116. X# include <stdio.h>
  1117. X# include <sys/types.h>
  1118. X# include <strings.h>
  1119. X# include "person.h"
  1120. X# include "args.h"            /* before luser.h */
  1121. X# include "luser.h"
  1122. X# include "finger.h"
  1123. X# include "inquire.h"
  1124. X
  1125. Xtypedef struct sel {
  1126. X    char *s_name;            /* name of selector (upper case) */
  1127. X                    /* for match against lusers */
  1128. X    int s_matches;            /* number of users matched */
  1129. X    char *s_orig;            /* name in living color (orig case) */
  1130. X                    /* for passwd file lookup */
  1131. X    struct switches s_sw;        /* per selector flags!! */
  1132. X    struct sel *s_next;            /* next in chain */
  1133. X} SEL;
  1134. X
  1135. Xextern PERSON *makeperson();        /* from getperson.c */
  1136. Xextern LTREE *linsert(), *ent_select();    /* from getent.c  */
  1137. Xextern LUSER *newluser();        /* from getent.c */
  1138. Xextern BOOL useinquire;            /* from args.c */
  1139. X
  1140. XLOCAL SEL *selhead;            /* chain of selectors */
  1141. XLOCAL SEL *seltail;            /* tail of selector chain */
  1142. X
  1143. XLOCAL LTREE *luser_tree;        /* tree of lusers from selectors */
  1144. X
  1145. XLOCAL LUSER *copy_not_found();        /* forward */
  1146. XLOCAL void insert_winner();        /* forward */
  1147. X
  1148. XGLOBAL void ini_select() {        /* initialize select.c statics */
  1149. X    selhead = seltail = NULL;
  1150. X    luser_tree = NULL;
  1151. X} /* ini_select */
  1152. X
  1153. XGLOBAL BOOL have_locals() {        /* find out if we have any SEL's */
  1154. X    return( selhead != NULL );
  1155. X} /* havelocal */
  1156. X
  1157. XGLOBAL void addlocal( name )        /* add a local finger selector */
  1158. Xchar *name;
  1159. X{
  1160. X    register SEL *new;
  1161. X
  1162. X    if( (new = (SEL *)malloc( sizeof( SEL ) )) == NULL ) {
  1163. X    fprintf(stderr, "malloc failed in sinsert\n");
  1164. X    exit( 1 );
  1165. X    } /* malloc failed */
  1166. X
  1167. X    new->s_orig = savestr( name );
  1168. X    new->s_name = name;
  1169. X    zup( name );
  1170. X    new->s_matches = 0;
  1171. X    new->s_sw = Sw;
  1172. X    new->s_next = NULL;
  1173. X
  1174. X    if( selhead == NULL )
  1175. X    selhead = seltail = new;
  1176. X    else {
  1177. X    seltail->s_next = new;
  1178. X    seltail = new;
  1179. X    }
  1180. X} /* addlocal */
  1181. X
  1182. XGLOBAL void select_go() {        /* here to finger local users */
  1183. X    struct passwd *pw;
  1184. X    LTREE *tree2;
  1185. X    int flag;
  1186. X    SEL *sp;
  1187. X
  1188. X    setpwent();
  1189. X    if( !useinquire ) {
  1190. X    while( (pw = getpwent()) != NULL ) {
  1191. X        LOCAL SEL *match();
  1192. X        SEL *winner;        /* the selector that matched */
  1193. X        char person[ 100 ], *tp;
  1194. X
  1195. X        if( selhead == NULL )
  1196. X        break;
  1197. X
  1198. X        /* BUG: handle USG format gecos fields!! */
  1199. X        /* copy gecos (WISH: only if comma)*/
  1200. X        strcpy( person, pw->pw_gecos );
  1201. X        if( (tp = index(person, ',')) != NULL ) /* find a comma? */
  1202. X        *tp = EOS;            /* yes, blast it. */
  1203. X
  1204. X        /* find a selector that matches uname or personal name */
  1205. X        winner = match( pw->pw_name, person );
  1206. X        if( winner != NULL )
  1207. X        insert_winner( winner, pw->pw_name, pw );
  1208. X    } /* while */
  1209. X    } /* no inquire */
  1210. X# ifdef INQUIRE
  1211. X    else {                /* use inquire */
  1212. X    struct block *bp;
  1213. X
  1214. X    for( sp = selhead; sp != NULL; sp = sp->s_next ) {
  1215. X        if( Read( sp->s_name, BPs ) != NULL )
  1216. X        insert_winner( sp, BPs[_UNAME], NULL, BPs );
  1217. X
  1218. X        if( sp->s_sw.sw_match )
  1219. X        continue;
  1220. X
  1221. X        /* Use FindPerson (inquire internal lastname lookup) */
  1222. X        for(bp = FindPerson( sp->s_name ); bp != NULL; /* find all */
  1223. X        bp = NextPerson( sp->s_name, bp) ){ /* matching lastnames */
  1224. X        Expand( bp, BPs );
  1225. X        insert_winner( sp, BPs[_UNAME], NULL, BPs );
  1226. X        } /* for matching persons */
  1227. X    } /* for each sel */
  1228. X    } /* useinquire */
  1229. X# endif /* INQUIRE defined */
  1230. X
  1231. X    /* one last try for unmatched selectors (or ones added by /follow!) */
  1232. X    for( sp = selhead; sp != NULL; sp = sp->s_next ) {
  1233. X    if( sp->s_matches == 0 ) {
  1234. X        struct passwd *pw;
  1235. X
  1236. X        pw = getpwnam( sp->s_orig );
  1237. X        if( pw != NULL )
  1238. X        insert_winner( sp, pw->pw_name, pw, NULL );
  1239. X    } /* no matches */
  1240. X    } /* for */
  1241. X
  1242. X    endpwent();
  1243. X
  1244. X    tree2 = ent_select( luser_tree );     /* get tree of logged in people */
  1245. X    tree2 = copy_not_found( luser_tree, tree2 ); /* merge people not on */
  1246. X
  1247. X    flag = 0;
  1248. X    for( sp = selhead; sp != NULL; sp = sp->s_next )
  1249. X    if( sp->s_matches == 0 ) {
  1250. X        if( flag == 0 )
  1251. X        fprintf(stderr, "%%No matches for ");
  1252. X        else
  1253. X        fputs( ", ", stderr );
  1254. X        fputs( sp->s_orig, stderr );
  1255. X        flag++;
  1256. X    }
  1257. X    if( flag > 0 )
  1258. X    putc( '\n', stderr );
  1259. X
  1260. X    if( tree2 != NULL )            /* get anything? */
  1261. X    dofinger( tree2 );
  1262. X} /* select_go */
  1263. X
  1264. X/* PERHAPS LUSERS SHOULD BE IN A LIST (avoid recursion) */
  1265. X/* see newluser in getent.c?  WISH */
  1266. X
  1267. X/* returns merged tree of logged in users and prototypes never found (NLI) */
  1268. X
  1269. XLOCAL LUSER *copy_not_found( proto, out )
  1270. XLUSER *proto, *out;            /* not logged in, output tree */
  1271. X{
  1272. X    if( proto != NULL ) {
  1273. X    /* travese bottom up, so safe to remove elements */
  1274. X    out = copy_not_found( proto->u_left, out );
  1275. X    out = copy_not_found( proto->u_right, out );
  1276. X    
  1277. X    if( (proto->u_flags & U_FOUND) == 0 ) {    /* proto never found? */
  1278. X        proto->u_left = proto->u_right = NULL; /* remove from tree */
  1279. X        out = linsert( proto, out ); /* insert into output tree */
  1280. X    } /* if not found */
  1281. X    } /* have a prototype */
  1282. X    return( out );
  1283. X} /* copy_not_found */
  1284. X
  1285. XLOCAL SEL *match(uname, fullname)    /* return a sel that matches */
  1286. Xchar *uname, *fullname;
  1287. X{
  1288. X    char *tp;
  1289. X    int nfull;
  1290. X    register SEL *sp;
  1291. X    char temp[ 512 ], temp2[ 512 ], *fullp[ 128 ];
  1292. X
  1293. X    strupcpy(temp, uname );        /* make upper case copy of uname */
  1294. X
  1295. X    nfull = 0;
  1296. X    if( fullname != NULL ) {
  1297. X    strupcpy(temp2, fullname);    /* copy personal, upper case */
  1298. X    tp = temp2;            /* point to fullname */
  1299. X    for( ; ; ) {
  1300. X        register char *bp;        /* pointer to start of token */
  1301. X
  1302. X        if( !skipwhite( &tp ) )    /* skip leading white */
  1303. X        break;
  1304. X
  1305. X        bp = tp;            /* save start of token */
  1306. X        if( !skipblack( &tp ) && bp == tp )
  1307. X        break;
  1308. X
  1309. X        *tp++ = EOS;        /* tie off token */
  1310. X        fullp[ nfull++ ] = bp;
  1311. X    } /* forever */
  1312. X    } /* have fullname */
  1313. X
  1314. X    for( sp = selhead; sp != NULL; sp = sp->s_next ) {
  1315. X    register int i;
  1316. X
  1317. X    if( strcmp( temp, sp->s_name ) == 0 )
  1318. X        return( sp );
  1319. X
  1320. X    if( sp->s_sw.sw_match        /* allow match on fullname? */
  1321. X       || nfull == 0 )        /* have one?? */
  1322. X        continue;
  1323. X
  1324. X    for( i = 0; i < nfull; i++ )
  1325. X        if( strcmp( fullp[i], sp->s_name ) == 0 )
  1326. X        return( sp );
  1327. X    }
  1328. X    return( NULL );
  1329. X} /* match */
  1330. X
  1331. XLOCAL void insert_winner( winner, uname, pw, inq )
  1332. XSEL *winner;
  1333. Xchar *uname;
  1334. Xstruct passwd *pw;
  1335. Xstruct info *inq;            /* for INQUIRE */
  1336. X{
  1337. X    register LUSER *u;
  1338. X
  1339. X    /* find a matching selector? is it in luser_tree already? */
  1340. X    if( winner == NULL  ||  treefind( luser_tree, uname ) != NULL )
  1341. X    return;
  1342. X    winner->s_matches++;        /* count our conquests */
  1343. X
  1344. X    if( pw == NULL ) {
  1345. X    pw = getpwnam( uname );
  1346. X# ifdef DEBUG
  1347. X    if( pw == NULL )
  1348. X        printf("no pw entry for %s\n", uname );
  1349. X# endif /* DEBUG defined */
  1350. X    }
  1351. X
  1352. X    /* found a new matching selector. create entry */
  1353. X
  1354. X    u = newluser();            /* create a user */
  1355. X    strcpy(u->u_user, uname);        /* set user name! */
  1356. X# ifdef INQUIRE
  1357. X    u->u_person = makeperson( u, pw, inq ); /* build person struct */
  1358. X# else  /* INQUIRE not defined */
  1359. X    u->u_person = makeperson( u, pw, NULL ); /* build person struct */
  1360. X# endif /* INQUIRE not defined */
  1361. X    u->u_flags |= U_NLI;        /* say not logged in */
  1362. X    u->u_sw = winner->s_sw;        /* inherit switched from SEL */
  1363. X    luser_tree = linsert(u, luser_tree);
  1364. X} /* insert_winner */
  1365. X
  1366. X/*
  1367. X * Local variables:
  1368. X * comment-column: 40
  1369. X * End:
  1370. X */
  1371. END_OF_select.c
  1372. if test 7584 -ne `wc -c <select.c`; then
  1373.     echo shar: \"select.c\" unpacked with wrong size!
  1374. fi
  1375. # end of overwriting check
  1376. fi
  1377. if test -f switch.c -a "${1}" != "-c" ; then 
  1378.   echo shar: Will not over-write existing file \"switch.c\"
  1379. else
  1380. echo shar: Extracting \"switch.c\" \(7158 characters\)
  1381. sed "s/^X//" >switch.c <<'END_OF_switch.c'
  1382. X/*
  1383. X * switch.c -- process switches (flags)    July 1987
  1384. X *
  1385. X * Copyright (C) 1987, 1990  Philip L. Budne
  1386. X *
  1387. X * This file is part of "Phil's Finger Program".
  1388. X *
  1389. X * This program is free software; you can redistribute it and/or modify
  1390. X * it under the terms of the GNU General Public License as published by
  1391. X * the Free Software Foundation; either version 1, or (at your option)
  1392. X * any later version.
  1393. X *
  1394. X */
  1395. X
  1396. X# ifndef lint
  1397. Xstatic char *rcsid = "$Id: switch.c,v 3.0 90/07/06 13:11:48 budd Rel $";
  1398. X# endif /* lint not defined */
  1399. X
  1400. X# include <stdio.h>
  1401. X# include <strings.h>
  1402. X# include <ctype.h>
  1403. X# include <signal.h>
  1404. X
  1405. X# ifndef sigmask
  1406. X# define sigmask(s) (1<<(s))
  1407. X# endif /* sigmask not defined */
  1408. X
  1409. X# include "args.h"
  1410. X# include "finger.h"
  1411. X
  1412. X# ifndef PAGER
  1413. X# define PAGER "more"
  1414. X# endif /* PAGER not defined */
  1415. X
  1416. X# ifndef BUGS_TO
  1417. X# define BUGS_TO "bug-finger@bu-it.bu.edu"
  1418. X# endif /* BUGS_TO not defined */
  1419. X
  1420. Xextern char *getenv();            /* libc */
  1421. Xextern char longversion[];        /* from version.c */
  1422. X
  1423. X# define SWITCH(s,u,a,h) LOCAL int a();
  1424. X# include "switch.h"            /* define forwards */
  1425. X# undef SWITCH
  1426. X
  1427. XLOCAL struct switchtab {
  1428. X    char *s_name;
  1429. X    int s_unique;
  1430. X    int (*s_ptr)();
  1431. X    char *s_help;
  1432. X} switches[] = {
  1433. X# define SWITCH(s,u,a,h) { s, u, a, h },
  1434. X# include "switch.h"            /* define table entries */
  1435. X# undef SWITCH
  1436. X    { NULL, NULL }
  1437. X};
  1438. X
  1439. X/*
  1440. X *    switch actions
  1441. X */
  1442. X
  1443. X# define SET2(what,name)    \
  1444. XLOCAL int CONC(set_,name) ( val ) char *val; \
  1445. X{ if( val != NULL )fprintf(stderr, "%%Switch %s takes no args\n", STR(name)); \
  1446. X  what = TRUE; return( TRUE ); }
  1447. X
  1448. X# define SETF(name) SET2(CONC(sw_,name),name)
  1449. X# define SETP(name) SET2(CONC(Sw.sw_,name),name)
  1450. X
  1451. XSETF(age);
  1452. XSETF(berkeley);
  1453. X# ifdef DEBUGSW
  1454. XSETF(debug);
  1455. X# endif /* DEBUGSW defined */
  1456. XSETF(follow);
  1457. XSETF(its);
  1458. XSETF(jobs);
  1459. XSETF(nosave);
  1460. XSETF(output);
  1461. XSETF(pid);
  1462. XSETF(read);
  1463. XSETF(state);
  1464. XSETF(whois);
  1465. X
  1466. X/* per person */
  1467. XSETP(location);
  1468. XSETP(mail);
  1469. XSETP(match);
  1470. XSETP(plan);
  1471. XSETP(noplan);
  1472. X
  1473. X# if 0
  1474. XLOCAL int set_fields( val )
  1475. Xchar *val;
  1476. X{
  1477. X    if( val == NULL ) {
  1478. X    sw_fields = ":";
  1479. X    return( TRUE );
  1480. X    }
  1481. X    sw_fields = val;
  1482. X    return( TRUE );
  1483. X} /* set fields */
  1484. X# endif /* 0 */
  1485. X
  1486. X# ifdef INQUIRE
  1487. XLOCAL int set_noinquire( val )
  1488. Xchar *val;
  1489. X{
  1490. X    extern BOOL useinquire;
  1491. X    useinquire = FALSE;
  1492. X    return( TRUE );
  1493. X} /* set noinquire */
  1494. X# endif /* INQUIRE defined */
  1495. X
  1496. XLOCAL int display_version( val )
  1497. Xchar *val;
  1498. X{
  1499. X    puts( longversion );
  1500. X# ifndef lint
  1501. X    puts( Copyright );
  1502. X# endif /* lint not defined */
  1503. X    exit( 0 );
  1504. X    return( TRUE );            /* supress complaints */
  1505. X}
  1506. X
  1507. XLOCAL FILE *openpager(pager, mode, pid)
  1508. X    char *pager, *mode;
  1509. X    int *pid;
  1510. X{
  1511. X    int pipefd[2], myend;
  1512. X    register c;
  1513. X
  1514. X    if( pipe(pipefd) < 0 ) {
  1515. X    perror( "pipe" );
  1516. X    return( NULL );
  1517. X    }
  1518. X
  1519. X    /* NOTE!! we depend on myend^1 being the other end */
  1520. X    /* and that the child will connect myend to fd myend */
  1521. X
  1522. X    if( *mode == 'r' )            /* parent reading? */
  1523. X    myend = 1;            /* child gets write/stdout */
  1524. X    else                /* parent writing. */
  1525. X    myend = 0;            /* child gets read/stdin */
  1526. X
  1527. X    switch( (*pid = fork()) ) {
  1528. X    case -1:
  1529. X    perror( "fork" );
  1530. X    close( pipefd[0] );        /* close reader */
  1531. X    close( pipefd[1] );        /* close writer */
  1532. X    return( NULL );
  1533. X
  1534. X    case 0:                /* child */
  1535. X    close( pipefd[myend^1] );    /* close other end */
  1536. X    if( pipefd[myend] != myend ) {    /* in place?? (unlikely) */
  1537. X        dup2( pipefd[myend], myend ); /* Nope, move it */
  1538. X        close( pipefd[ myend ] );
  1539. X    } /* not yet in place */
  1540. X    setuid( getuid() );        /* remove any setuidness!!! */
  1541. X    setgid( getgid() );
  1542. X    execlp( pager, pager, 0 );    /* forgo doing "sh -c cmd" */
  1543. X    perror( pager );
  1544. X    while( (c = getchar()) != EOF )    /* whoops!! Just copy bytes! */
  1545. X        putchar( c );
  1546. X    exit( 0 );
  1547. X    /* NOTREACHED */
  1548. X
  1549. X    default:                /* parent */
  1550. X    myend ^= 1;            /* parent gets other end */
  1551. X    close( pipefd[myend^1] );    /* close childs end */
  1552. X    return( fdopen( pipefd[myend], mode ) ); /* use "rw"[myend] ?? */
  1553. X                    /* check for failure!! */
  1554. X    } /* switch */
  1555. X    /* NOTREACHED */
  1556. X} /* openpager */
  1557. X
  1558. XLOCAL int closepager( f, pid )
  1559. X    FILE *f;
  1560. X    int pid;
  1561. X{
  1562. X    int pid2, w, smask;
  1563. X
  1564. X    fclose( f );
  1565. X# ifndef USG
  1566. X    smask = sigblock( sigmask(SIGHUP) | sigmask(SIGQUIT) | sigmask(SIGINT) );
  1567. X# else  /* USG defined */
  1568. X# ifdef SIGPOLL                /* SVR3 signaling */
  1569. X    sighold( SIGHUP );
  1570. X    sighold( SIGQUIT );
  1571. X    sighold( SIGINT );
  1572. X# endif /* SIGPOLL defined */
  1573. X# endif /* USG defined */
  1574. X
  1575. X    while( (pid2 = wait(&w)) != -1 && pid2 != pid )
  1576. X    printf("%d %d\n", pid, pid2);
  1577. X
  1578. X# ifndef USG
  1579. X    sigsetmask( smask );
  1580. X# else  /* USG defined */
  1581. X# ifdef SIGPOLL                /* SVR3 signaling features */
  1582. X    sigrelse( SIGHUP );
  1583. X    sigrelse( SIGQUIT );
  1584. X    sigrelse( SIGINT );
  1585. X# endif /* SIGPOLL defined */
  1586. X# endif /* USG defined */
  1587. X
  1588. X    if( pid2 == -1 )
  1589. X    return( -1 );            /* process not found? */
  1590. X    return( w );            /* return (whole) status */
  1591. X} /* closepager */
  1592. X
  1593. XLOCAL int display_help( val )
  1594. Xchar *val;
  1595. X{
  1596. X    static char help_format[] = "%-15s %s\n"; /* just one copy */
  1597. X    register struct switchtab *sp;
  1598. X    char *pager;
  1599. X    int pid;
  1600. X    FILE *p;
  1601. X
  1602. X    if( (pager = getenv("PAGER")) == NULL )
  1603. X    pager = PAGER;
  1604. X
  1605. X    if( !isatty(STD_INPUT) || (p = openpager( pager, "w", &pid )) == NULL ) {
  1606. X    pager = NULL;            /* oh well */
  1607. X    p = stdout;
  1608. X    } /* openpager failed */
  1609. X
  1610. X    fprintf( p, "finger/whois help:\n");
  1611. X    fprintf( p, "%s\n",  longversion );
  1612. X# ifndef lint
  1613. X    fprintf( p, "%s\n",  Copyright );
  1614. X# endif /* lint not defined */
  1615. X    fprintf( p, "\n\
  1616. Xfinger accepts the following as arguments:\n\
  1617. Xlocal usernames, local personal names, switches (/sw or -sw),\n\
  1618. Xterminal names (+tty0d +0d), self (.), or remote (@host, user@host)\n\
  1619. X\n");
  1620. X    fprintf( p, help_format, "switch", "action");
  1621. X    fprintf( p, help_format, "======", "======");
  1622. X    for( sp = switches; sp->s_help != NULL; sp++ )
  1623. X    fprintf( p, help_format, sp->s_name, sp->s_help );
  1624. X    fprintf( p, "\n");
  1625. X    fprintf( p, "for more information type 'man finger', bugs to %s\n",
  1626. X        BUGS_TO );
  1627. X    fflush( p );
  1628. X    if( pager != NULL )            /* have pager process? */
  1629. X    closepager( p, pid );        /* be tidy */
  1630. X    exit( 0 );
  1631. X    return( TRUE );            /* keep gcc quiet */
  1632. X} /* display_help */
  1633. X
  1634. XGLOBAL void doswitch( cp )        /* see also args.h */
  1635. Xregister char *cp;
  1636. X{
  1637. X    register char *tp, *vp, *ttp;
  1638. X    register struct switchtab *sp;
  1639. X    register len;
  1640. X    int match;
  1641. X
  1642. X    for( ; cp != NULL ; cp = tp ) {
  1643. X    tp = index( cp, '/' );
  1644. X    if( tp != NULL )
  1645. X        *tp++ = EOS;
  1646. X
  1647. X    if( (vp = index(cp,':')) != NULL )
  1648. X        *vp++ = EOS;
  1649. X
  1650. X    len = strlen( cp );
  1651. X    if( len == 0 )
  1652. X        continue;
  1653. X
  1654. X    for( ttp = cp; *ttp != EOS; ttp++ )
  1655. X        if( isupper( *ttp ) )
  1656. X        *ttp = tolower( *ttp );
  1657. X
  1658. X    match = 0;
  1659. X    sp = switches;
  1660. X    while( sp->s_name != NULL ) {
  1661. X        if( strncmp(cp, sp->s_name, len) == 0 ) {
  1662. X        match++;
  1663. X        if( len >= sp->s_unique ) {
  1664. X            (void) (*(sp->s_ptr))( vp );
  1665. X            match = 1;        /* force uniqueness */
  1666. X            break;
  1667. X        }
  1668. X        } /* if strncmp [i] */
  1669. X        sp++;
  1670. X    } /* while */
  1671. X    if( match > 1 ) {
  1672. X        fprintf(stderr, "?Ambiguous switch '%s'. Use /help for help\n",
  1673. X            cp );
  1674. X        exit( 1 );
  1675. X    }
  1676. X    else if( sp->s_name == NULL ) {
  1677. X        fprintf(stderr, "?Unknown switch '%s'. Use /help for help\n", cp );
  1678. X        exit( 1 );
  1679. X    }
  1680. X    } /* for ever */
  1681. X} /* doswitch */
  1682. X
  1683. X/*
  1684. X * Local variables:
  1685. X * comment-column: 40
  1686. X * End:
  1687. X */
  1688. END_OF_switch.c
  1689. if test 7158 -ne `wc -c <switch.c`; then
  1690.     echo shar: \"switch.c\" unpacked with wrong size!
  1691. fi
  1692. # end of overwriting check
  1693. fi
  1694. if test -f whois.c -a "${1}" != "-c" ; then 
  1695.   echo shar: Will not over-write existing file \"whois.c\"
  1696. else
  1697. echo shar: Extracting \"whois.c\" \(7273 characters\)
  1698. sed "s/^X//" >whois.c <<'END_OF_whois.c'
  1699. X/*
  1700. X * whois -- user info output for new finger
  1701. X *
  1702. X * Copyright (C) 1986, 1990  Philip L. Budne
  1703. X *
  1704. X * This file is part of "Phil's Finger Program".
  1705. X *
  1706. X * This program is free software; you can redistribute it and/or modify
  1707. X * it under the terms of the GNU General Public License as published by
  1708. X * the Free Software Foundation; either version 1, or (at your option)
  1709. X * any later version.
  1710. X *
  1711. X */
  1712. X
  1713. X# ifndef lint
  1714. Xstatic char *rcsid = "$Id: whois.c,v 3.0 90/07/06 13:12:18 budd Rel $";
  1715. X# endif /* lint not defined */
  1716. X
  1717. X# include "finger.h"
  1718. X# include <sys/types.h>
  1719. X# include <sys/stat.h>
  1720. X# include <sys/time.h>
  1721. X# include <strings.h>
  1722. X# include <stdio.h>
  1723. X# include <ctype.h>
  1724. X# if defined(AUX) || defined(AIX3)
  1725. X# include <time.h>            /* bus-ted */
  1726. X# endif /* defined(AUX) || defined(AIX3) */
  1727. X# include <pwd.h>
  1728. X# include <grp.h>
  1729. X# include "person.h"
  1730. X# include "args.h"            /* sw_its (before luser.h) */
  1731. X# include "luser.h"
  1732. X# include "output.h"
  1733. X
  1734. XEXTERN void outline();            /* from output.c */
  1735. XEXTERN char *acct_name();        /* from conf.c */
  1736. XEXTERN char *office();            /* from acct.c */
  1737. XEXTERN struct group *getgrent();    /* USG grp.h loses */
  1738. X
  1739. XFORWARD GLOBAL char *nicetime();
  1740. X
  1741. XLOCAL char line[MAXLINE];
  1742. X
  1743. XLOCAL void newline() {
  1744. X    if( line[0] != EOS ) {
  1745. X    outline( line );
  1746. X    line[0] = EOS;
  1747. X    } /* non-empty */
  1748. X} /* newline */
  1749. X
  1750. XLOCAL void checksemi() {
  1751. X    if( line[0] != EOS )
  1752. X    strcat(line, ";");
  1753. X} /* checksemi */
  1754. X
  1755. XGLOBAL void whois( u )
  1756. Xregister LUSER *u;
  1757. X{
  1758. X    char tbuf[ 100 ];
  1759. X    register PERSON *p;
  1760. X    struct group *gr;
  1761. X    char **members, *acctname;
  1762. X
  1763. X    line[0] = EOS;
  1764. X
  1765. X    p = u->u_person;        /* get person structure */
  1766. X    if( p != NULL ) {
  1767. X    if( p->p_nickname != NULL ) {
  1768. X        strcat(line, "  (");
  1769. X        strcat(line, p->p_nickname);
  1770. X        strcat(line, ")");
  1771. X    } /* nickname */
  1772. X
  1773. X# ifdef notdef                /* shown below (in mcheck) */
  1774. X    if( p->p_maddr != NULL ) {
  1775. X        strcat(line, "  [" );
  1776. X        strcat(line, p->p_maddr );
  1777. X        strcat(line, "]");
  1778. X    } /* mail address */
  1779. X# endif /* notdef defined */
  1780. X
  1781. X    acctname = acct_name( p );
  1782. X    if( p->p_project != NULL || p->p_supervisor != NULL ||
  1783. X       acctname != NULL ) {
  1784. X# ifdef DONT_SAY_HACKING        /* some people confuse hackers */
  1785. X        strcat(line, "  working ");    /* and crackers!! */
  1786. X# else  /* DONT_SAY_HACKING not defined */
  1787. X        strcat(line, "  Hacking ");
  1788. X# endif /* DONT_SAY_HACKING not defined */
  1789. X        if( p->p_project != NULL ) {
  1790. X# ifdef DONT_SAY_HACKING
  1791. X        strcat(line, " on ");
  1792. X# endif /* DONT_SAY_HACKING defined */
  1793. X        strcat(line, p->p_project);
  1794. X        strcat(line, " ");
  1795. X        } /* project */
  1796. X        if( p->p_supervisor != NULL || acctname != NULL ) {
  1797. X        strcat(line, "for ");
  1798. X        if( p->p_supervisor != NULL )
  1799. X            strcat(line, p->p_supervisor);
  1800. X        else {
  1801. X            strcat(line, acctname ); /* *TODO* do this in getperson? */
  1802. X            acctname = NULL;    /* don't repeat this! */
  1803. X        }
  1804. X        } /* super */
  1805. X    } /* project or super */
  1806. X
  1807. X    newline();
  1808. X
  1809. X    if( p->p_birthday != NULL ) {
  1810. X        strcat(line, "  Birthday ");
  1811. X        strcat(line, p->p_birthday);
  1812. X    } /* birthday */
  1813. X
  1814. X    if( p->p_waddr != NULL || p->p_wphone != NULL ) {
  1815. X        checksemi();
  1816. X        strcat(line, "  Work ");
  1817. X        if( p->p_waddr != NULL ) {
  1818. X        strcat(line, p->p_waddr );
  1819. X        if( p->p_wphone != NULL ) {
  1820. X            strcat(line, "; ");
  1821. X            catphone(line, p->p_wphone );
  1822. X        } /* waddr and wphone */
  1823. X        } /* one of waddr and wphone */
  1824. X        else
  1825. X        catphone(line, p->p_wphone);
  1826. X    } /* work address or phone */
  1827. X
  1828. X    newline();
  1829. X
  1830. X    if( p->p_haddr != NULL || p->p_hphone != NULL ) {
  1831. X        strcat(line, "  Home ");
  1832. X        if( p->p_haddr != NULL ) {
  1833. X        strcat(line, p->p_haddr );
  1834. X        if( p->p_hphone != NULL ) {
  1835. X            strcat(line, "; ");
  1836. X            catphone(line, p->p_hphone );
  1837. X        } /* addr and phone */
  1838. X        } /* one of addr and phone */
  1839. X        else
  1840. X        catphone(line, p->p_hphone);
  1841. X    } /* home address or phone */
  1842. X
  1843. X    /**************** dull stuff ****************/
  1844. X    newline();
  1845. X    if( p->p_home != NULL ) {
  1846. X        struct passwd *pw;
  1847. X        char *acn;
  1848. X
  1849. X        sprintf(tbuf, "  [%d,%d]", p->p_uid, p->p_gid );
  1850. X        strcat(line, tbuf);
  1851. X
  1852. X        strcat(line, "  <");
  1853. X        strcat(line, p->p_home);
  1854. X        strcat(line, ">");
  1855. X
  1856. X        acn = NULL;
  1857. X        if( (gr = getgrgid( p->p_gid )) != NULL )
  1858. X        acn = gr->gr_name;
  1859. X# ifndef NO_COMMON_NAMESPACE        /* uid's and gid's use same names @bu */
  1860. X        else if( (pw = getpwuid( p->p_gid )) != NULL ) /* NOTE: gid! */
  1861. X        acn = pw->pw_name;
  1862. X# endif /* NO_COMMON_NAMESPACE not defined */
  1863. X        else
  1864. X        acn = acctname;
  1865. X
  1866. X        if( acn != NULL ) {
  1867. X        checksemi();
  1868. X        strcat(line, "  Group: ");
  1869. X        strcat(line, acn );
  1870. X        }
  1871. X        if( p->p_shell != NULL ) {
  1872. X        strcat(line, "  Shell: ");
  1873. X        strcat(line, p->p_shell);
  1874. X        } /* unusual shell */
  1875. X    } /* has home (password entry) */
  1876. X
  1877. X    newline();
  1878. X    } /* has person struct */
  1879. X
  1880. X    setgrent();
  1881. X    tbuf[0] = EOS;
  1882. X    while( (gr = getgrent()) != NULL ) {
  1883. X    for( members = gr->gr_mem; *members != NULL; members++ ) {
  1884. X        if( strcmp( u->u_user, *members ) == 0 ) {
  1885. X        strcat( tbuf, " " );    /* add a space */
  1886. X        strcat( tbuf, gr->gr_name ); /* add name */
  1887. X        break;
  1888. X        } /* match */
  1889. X    } /* while members */
  1890. X    } /* while gr */
  1891. X    endgrent();
  1892. X
  1893. X    if( tbuf[0] != EOS ) {
  1894. X    strcpy(line, "  Groups:");
  1895. X    strcat(line, tbuf );
  1896. X    newline();
  1897. X    } /* found groups */
  1898. X
  1899. X} /* whois */
  1900. X
  1901. X# define PLANBUFLEN 200
  1902. XGLOBAL BOOL plan( u )
  1903. XLUSER *u;
  1904. X{
  1905. X    char buf[PLANBUFLEN];
  1906. X    struct stat st;
  1907. X    PERSON *p;
  1908. X    FILE *f;
  1909. X
  1910. X    if( (p = u->u_person) == NULL || p->p_home == NULL || p->p_home[0] == EOS )
  1911. X    return( FALSE );
  1912. X
  1913. X    strcpy(buf, p->p_home);
  1914. X    strcat(buf, "/.plan");
  1915. X
  1916. X    if( (f = fopen(buf, "r")) == NULL )
  1917. X        return( FALSE );
  1918. X
  1919. X    if( fstat( fileno(f), &st ) < 0 )
  1920. X    outline("  Plan:");
  1921. X    else {
  1922. X    sprintf( buf, "  Plan: (last modified %s)", nicetime( st.st_mtime ) );
  1923. X    outline( buf );
  1924. X    }
  1925. X
  1926. X    while( fgets(buf, PLANBUFLEN, f) != NULL ) {
  1927. X    register char *cp;
  1928. X    if( (cp = index(buf, '\n')) != NULL )
  1929. X        *cp = EOS;
  1930. X# ifndef DONT_TAB_PLAN
  1931. X    outchar('\t');
  1932. X# endif /* DONT_TAB_PLAN not defined */
  1933. X    outline( buf );
  1934. X    } /* while */
  1935. X    fclose( f );
  1936. X    return( TRUE );
  1937. X} /* plan */
  1938. X
  1939. XLOCAL char *weekday[] = {
  1940. X    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
  1941. X};
  1942. X
  1943. XLOCAL char *month[] = {
  1944. X    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  1945. X    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  1946. X};
  1947. X
  1948. XGLOBAL char *nicetime( t )
  1949. Xtime_t t;
  1950. X{
  1951. X    struct tm *tm, *localtime();
  1952. X    static char buffer[100];
  1953. X    char *am;
  1954. X    int hour;
  1955. X
  1956. X    tm = localtime( &t );
  1957. X    if( sw_its ) {            /* format date/time like ITS */
  1958. X    sprintf( buffer, "%02d/%02d/%02d %02d:%02d:%02d",
  1959. X        tm->tm_mon+1, tm->tm_mday, tm->tm_year,
  1960. X        tm->tm_hour,  tm->tm_min, tm->tm_sec );
  1961. X    return( buffer );
  1962. X    } /* ITS */
  1963. X
  1964. X    hour = tm->tm_hour;
  1965. X    am = "AM";
  1966. X    if( hour == 0 )            /* fix midnight */
  1967. X    hour = 12;
  1968. X    else if( hour > 11 ) {        /* after 11AM */
  1969. X    am = "PM";            /* its after-noon */
  1970. X    if( hour > 12 )            /* but don't touch 12!! */
  1971. X        hour -= 12;
  1972. X    } /* PM */
  1973. X
  1974. X    sprintf(buffer, "%s %d-%s-%d %d:%02d%s",
  1975. X        weekday[tm->tm_wday], tm->tm_mday,
  1976. X        month[tm->tm_mon], tm->tm_year,
  1977. X        hour, tm->tm_min, am);
  1978. X
  1979. X    return( buffer );
  1980. X} /* nicetime */
  1981. X
  1982. XGLOBAL void remarks(u)
  1983. XLUSER *u;
  1984. X{
  1985. X    PERSON *p;
  1986. X    register char *cp;
  1987. X
  1988. X    p = u->u_person;
  1989. X    if( p != NULL && p->p_remarks != NULL ) {
  1990. X    cp = p->p_remarks;
  1991. X    while( *cp != EOS )
  1992. X        outchar( *cp++ );
  1993. X    } /* have person and remarks */
  1994. X} /* remarks */
  1995. X
  1996. X/*
  1997. X * Local variables:
  1998. X * comment-column: 40
  1999. X * End:
  2000. X */
  2001. END_OF_whois.c
  2002. if test 7273 -ne `wc -c <whois.c`; then
  2003.     echo shar: \"whois.c\" unpacked with wrong size!
  2004. fi
  2005. # end of overwriting check
  2006. fi
  2007. if test -f ymakefile -a "${1}" != "-c" ; then 
  2008.   echo shar: Will not over-write existing file \"ymakefile\"
  2009. else
  2010. echo shar: Extracting \"ymakefile\" \(7929 characters\)
  2011. sed "s/^X//" >ymakefile <<'END_OF_ymakefile'
  2012. X/*
  2013. X * ymakefile -- cpp input file for real work makefile (xmakefile)
  2014. X *
  2015. X * Copyright (C) 1986, 1990  Philip L. Budne
  2016. X *
  2017. X * This file is part of "Phil's Finger Program".
  2018. X *
  2019. X * This program is free software; you can redistribute it and/or modify
  2020. X * it under the terms of the GNU General Public License as published by
  2021. X * the Free Software Foundation; either version 1, or (at your option)
  2022. X * any later version.
  2023. X *
  2024. X */
  2025. X
  2026. X/*
  2027. X * $Id: ymakefile,v 3.1 90/07/06 13:21:28 budd Exp $
  2028. X */
  2029. X
  2030. X/* Needed under AIX_RT */
  2031. XSHELL=/bin/sh
  2032. X
  2033. X# include "local.h"
  2034. X
  2035. X/* Used for make depend */
  2036. X/* CCM=cc -M */
  2037. XCCM=./cc-M
  2038. X
  2039. XETAGS=etags
  2040. XDIST=/usr/public/users/budd/finger
  2041. X
  2042. X# ifdef C_COMPILER
  2043. XCC=C_COMPILER
  2044. X# else  /* C_COMPILER not defined */
  2045. X# ifdef ibm032
  2046. XCC=pcc
  2047. X# endif /* ibm032 defined */
  2048. X# endif /* C_COMPILER not defined */
  2049. X
  2050. X# ifdef C_FLAGS
  2051. XCC_FLAGS=C_FLAGS
  2052. X# else  /* C_FLAGS not defined */
  2053. XCC_FLAGS=-O
  2054. X# endif /* C_FLAGS not defined */
  2055. X
  2056. X# ifdef LD_FLAGS
  2057. X/* useful for -Bstatic on SunOS4 */
  2058. XLDFLAGS=LD_FLAGS
  2059. X# endif /* LD_FLAGS defined */
  2060. X
  2061. X# ifdef INQUIRE
  2062. XLINQUIRE=./hakinq/libinq.a
  2063. X# endif /* INQUIRE defined */
  2064. X
  2065. X# ifdef USG
  2066. XTERM=-lcurses
  2067. X# else  /* USG not defined */
  2068. XTERM=-ltermcap
  2069. X# endif /* USG not defined */
  2070. X
  2071. X# if SunOS >= 40
  2072. X# ifdef i386
  2073. XOSLIBS=-lkvm -lld
  2074. X# else  /* i386 not defined */
  2075. XOSLIBS=-lkvm
  2076. X# endif /* i386 not defined */
  2077. X# endif /* SunOS >= 40 */
  2078. X
  2079. X# ifdef sgi
  2080. X/* -lsun for yp -- per spike@world.std.com */
  2081. X# ifdef YELLOW_PAGES
  2082. XOSLIBS=-lbsd -lmld -lsun
  2083. X# else  /* YELLOW_PAGES not defined */
  2084. XOSLIBS=-lbsd -lmld
  2085. X# endif /* YELLOW_PAGES not defined */
  2086. XINCLUDES=-I/usr/include/bsd
  2087. X# endif /* sgi defined */
  2088. X
  2089. X# ifdef AIX3
  2090. XOSLIBS=-lcfg -lodm
  2091. X# endif /* AIX3 defined */
  2092. X
  2093. X# ifdef UmaxV
  2094. X/* recent versions have /bsd/usr/include... /bsd/bin/cc... etc */
  2095. XOSLIBS=-laux
  2096. XINCLUDES=-I./include
  2097. X# endif /* UmaxV defined */
  2098. X
  2099. X# ifdef SYSI86                /* Interactive 386/ix */
  2100. XOSLIBS=-linet
  2101. X# endif /* SYSI86 defined */
  2102. X
  2103. X# if Umax == 43
  2104. XOSLIBS=-lld
  2105. X# endif /* Umax == 43 */
  2106. X
  2107. X# ifdef LIB_RESOLVE
  2108. XRESOLVE=LIB_RESOLVE
  2109. X# endif /* LIB_RESOLVE defined */
  2110. X
  2111. X# ifdef INCLUDE_PATH
  2112. XINCLUDES=INCLUDE_PATH
  2113. X# endif /* INCLUDE_PATH defined */
  2114. X
  2115. X# ifdef USG
  2116. XOTHERS=uptime
  2117. X# endif /* USG defined */
  2118. X
  2119. X# ifdef NO_STRINGS_H
  2120. XOSINCLUDES=-I.
  2121. X# endif /* NO_STRINGS_H defined */
  2122. X
  2123. XCFLAGS=$(CC_FLAGS) $(OSINCLUDES) $(INCLUDES) 
  2124. X
  2125. X/****************************************************************
  2126. X */
  2127. XALL=    xf fingerd ttyloc ttyask $(OTHERS)
  2128. X
  2129. X/* for cleanup */
  2130. XALLBIN= $(ALL) symdate pversion newmanifest mywhoami
  2131. X
  2132. Xall:    $(ALL)
  2133. X
  2134. X.PRECIOUS: $(ALL)
  2135. X
  2136. X/****************************************************************
  2137. X * (internet) finger daemon
  2138. X */
  2139. X
  2140. X/* Add new files to MANIFEST!! */
  2141. XFINGERD_O=fingerd.o string.o upper.o
  2142. Xfingerd: $(FINGERD_O)
  2143. X    $(CC) $(CFLAGS) -o fingerd $(FINGERD_O) $(RESOLVE) $(OSLIBS) $(LDFLAGS)
  2144. X# ifdef IN_DOT_DAEMON
  2145. X    -rm -f in.fingerd
  2146. X    ln fingerd in.fingerd
  2147. X# endif /* IN_DOT_DAEMON defined */
  2148. X
  2149. X/****************************************************************
  2150. X * new finger!
  2151. X */
  2152. X/* Add new files to MANIFEST!! */
  2153. XNF_O=    args.o daemon.o doremote.o conf.o finger.o getcommand.o\
  2154. X    getent.o getperson.o getttyloc.o getut.o global.o inquire.o\
  2155. X    kmem.o lastlog.o locname.o mcheck.o names.o output.o readpr.o\
  2156. X    ttylocfile.o read_vmunix.o select.o skip.o string.o switch.o\
  2157. X    undomain.o upper.o ustruct.o whois.o whoj.o
  2158. X
  2159. XNF_C=    args.c daemon.c doremote.c conf.c finger.c getcommand.c\
  2160. X    getent.c getperson.c getttyloc.c getut.c global.c inquire.c\
  2161. X    kmem.c lastlog.c locname.c mcheck.c names.c output.c readpr.c\
  2162. X    ttylocfile.c read_vmunix.c select.c skip.c string.c switch.c\
  2163. X    undomain.c upper.c ustruct.c whois.c whoj.c
  2164. X
  2165. XNFLIBS=    $(TERM) $(RESOLVE) $(LINQUIRE) $(OSLIBS)
  2166. X
  2167. Xxf:    $(NF_O) pversion mywhoami
  2168. X    ./make-version > version.c
  2169. X    $(CC) -c version.c
  2170. X    $(CC) $(CFLAGS) -o xf $(NF_O) version.o $(NFLIBS) $(LDFLAGS)
  2171. X
  2172. Xpversion: pversion.c History.h
  2173. X    $(CC) $(CFLAGS) -o pversion pversion.c
  2174. X
  2175. X/* whoami is a BSDism.  USG systems don't have it */
  2176. Xmywhoami: mywhoami.c
  2177. X    $(CC) $(CFLAGS) -o mywhoami mywhoami.c
  2178. X
  2179. X/* uptime replacement for USG systems */
  2180. X# ifdef USG
  2181. Xuptime:    uptime.c
  2182. X    $(CC) $(CFLAGS) -o uptime uptime.c
  2183. X# endif /* USG defined */
  2184. X
  2185. X# ifdef UmaxV
  2186. X/* newer releases have /bsd/usr/include */
  2187. X$(NF_O): ./include
  2188. X
  2189. X./include:
  2190. X    mkdir include include/sys
  2191. X    (cd include; \
  2192. X     ln -s /usr/include/sys/arpa /usr/include/sys/netinet .; \
  2193. X     ln -s /usr/include/sys/aux/syslog.h /usr/include/sys/aux/netdb.h .; \
  2194. X     cd sys; ln -s /usr/include/sys/h/socket.h . )
  2195. X# endif /* UmaxV defined */
  2196. X
  2197. Xsymdate.h: symdate syms.h
  2198. X    ./symdate syms.h > symdate.h
  2199. X
  2200. Xsymdate: symdate.c
  2201. X    $(CC) -o symdate symdate.c
  2202. X
  2203. X/****************
  2204. X * create call graph.  (-c and -W are BU local switches)
  2205. X */
  2206. Xxf.calls: $(NF_C)
  2207. X    calls -W 4 -c -e -f main $(NF_C) > xf.calls
  2208. X
  2209. XTAGS:    $(NF_C)
  2210. X    $(ETAGS) $(NF_C) 
  2211. X
  2212. X/****************************************************************
  2213. X * Interactive ttyloc asker (front end for ttyloc)
  2214. X */
  2215. X
  2216. XTTYASK= ttyask.o skip.o getttytype.o ttylocfile.o string.o upper.o
  2217. Xttyask:    $(TTYASK)
  2218. X    $(CC) $(CFLAGS) -o ttyask $(TTYASK) $(OSLIBS) $(LDFLAGS)
  2219. X
  2220. X/****************************************************************
  2221. X * ttyloc setting program
  2222. X */
  2223. X
  2224. XTTYLOC=    ttyloc.o locname.o
  2225. Xttyloc:    $(TTYLOC)
  2226. X    $(CC) $(CFLAGS) -o ttyloc $(TTYLOC) $(OSLIBS) $(LDFLAGS)
  2227. X
  2228. X/****************************************************************
  2229. X * lint picking
  2230. X */
  2231. X
  2232. X/* removed -p -- not in SunOS anymore!! */
  2233. Xlint:    llib-lf.ln
  2234. X    lint -h llib-lf.ln *.c > LINT 2>&1
  2235. X
  2236. Xllib-lf.ln:
  2237. X    lint -Cf $(DEFS) *.c > /dev/null 2>&1
  2238. X
  2239. X/****************************************************************
  2240. X * household chores
  2241. X */
  2242. XKIT=Finger-part
  2243. X/*
  2244. X * be tidy (keeps .o files)
  2245. X *
  2246. X * kill myecho, pversion, and symdate as they are compiled
  2247. X * and don't port across achitectures!
  2248. X */
  2249. X
  2250. Xclean:
  2251. X    -rm -f core *~ \#* *.out finger.tar *.bak LOG *.s $(KIT)* \
  2252. X        MANIFEST.* myecho pversion symdate mywhoami getgroup checkmode
  2253. X
  2254. Xrealclean: clean
  2255. X    -rm -f $(ALLBIN) *.o version.c local.h \
  2256. X        xmakefile Install in.fingerd
  2257. X
  2258. X/*
  2259. X * pack up using tar or makekit
  2260. X */
  2261. X
  2262. X/* If you add here, you MUST add to MANIFEST too!! */
  2263. XSAMPLE=SAMPLE-local.h
  2264. XSAMPLE2=SAMPLE-flags
  2265. XSAMPLE3=SAMPLE-conf
  2266. XSAMPLES=$(SAMPLE) $(SAMPLE2) SAMPLE-nttyloc $(SAMPLE3)
  2267. XTAR=    VERSION* COPYRIGHT COPYING Cover README\
  2268. X    finger.1 ttyloc.1 nttyloc.5 finger.conf.5 fingerd.8c\
  2269. X    Makefile ymakefile Install.cpp autoconfig make-version\
  2270. X    TODO WISHES COUNT ORIG FINDDEFS DIFFALL COMDEFALL defs.awk cc-M\
  2271. X    MODES $(SAMPLES) Distfile\
  2272. X    `ls *.[ch] | egrep -v '^(local\.h|version\.c|symdate\.h)'`
  2273. X
  2274. X$(SAMPLE): local.h
  2275. X    rm -f $(SAMPLE)
  2276. X    cp local.h $(SAMPLE)
  2277. X
  2278. X$(SAMPLE2):
  2279. X    -cp local-flags $(SAMPLE2) || touch $(SAMPLE2)
  2280. X
  2281. X$(SAMPLE3):
  2282. X    -cp finger.conf $(SAMPLE3) || touch $(SAMPLE3)
  2283. X
  2284. Xfinger.tar tar: $(SAMPLES) pversion mywhoami
  2285. X    -rm -f VERSION*
  2286. X# ifndef USG
  2287. X    echo "`date` by `./mywhoami` on `hostname`" > VERSION-`pversion`
  2288. X# endif /* USG not defined */
  2289. X    tar cf finger.tar $(TAR) hungry
  2290. X
  2291. Xfinger.tar.Z: finger.tar
  2292. X    compress -v < finger.tar > finger.tar.Z
  2293. X
  2294. Xsplit:    finger.tar.Z
  2295. X    uuencode finger.tar.Z < finger.tar.Z | split - finger.tar.Z.uu.
  2296. X
  2297. X/* utter crock to merge file list and MANIFEST! */
  2298. Xnewmanifest: newmanifest.c
  2299. X    $(CC) $(CFLAGS) -o newmanifest newmanifest.c
  2300. X
  2301. X/* note; hungry/?* to defeat cpp comment removal!! */
  2302. Xkit:    $(SAMPLES) pversion newmanifest
  2303. X    -rm -f VERSION* $(KIT)*
  2304. X    echo "version `pversion` packed `date` by `whoami` on `hostname`" > \
  2305. X        VERSION
  2306. X    cp MANIFEST MANIFEST.saved
  2307. X    ./newmanifest $(TAR) hungry hungry/?* MANIFEST > nMANIFEST
  2308. X    mv nMANIFEST MANIFEST
  2309. X    makekit -n $(KIT) -s 64k -m
  2310. X    rm -f MANIFEST.BAK
  2311. X
  2312. Xdist:    kit split
  2313. X    rm -rf $(DIST)
  2314. X    mkdir $(DIST) $(DIST)/shar $(DIST)/split
  2315. X    cp README COPYING $(DIST)
  2316. X    mv finger.tar finger.tar.Z VERSION* $(DIST)
  2317. X    mv $(KIT)* $(DIST)/shar
  2318. X    mv finger.tar.Z.uu.?? $(DIST)/split
  2319. X
  2320. Xdepend:
  2321. X    sed '/^# DO NOT DELETE THIS LINE/q' xmakefile > xmakefile.tmp
  2322. X    $(CCM) $(CFLAGS) *.c |\
  2323. X        egrep -v '(local\.h|finger\.h|/usr/include|.c:$$|.c$$)' |\
  2324. X        sed 's@[     ]*\./@ @' >> xmakefile.tmp
  2325. X    mv xmakefile.tmp xmakefile
  2326. X
  2327. X/* ugh.  cannot trust make depend the first time around */
  2328. Xnames.o: symdate.h
  2329. END_OF_ymakefile
  2330. if test 7929 -ne `wc -c <ymakefile`; then
  2331.     echo shar: \"ymakefile\" unpacked with wrong size!
  2332. fi
  2333. # end of overwriting check
  2334. fi
  2335. echo shar: End of archive 4 \(of 7\).
  2336. cp /dev/null ark4isdone
  2337. MISSING=""
  2338. for I in 1 2 3 4 5 6 7 ; do
  2339.     if test ! -f ark${I}isdone ; then
  2340.     MISSING="${MISSING} ${I}"
  2341.     fi
  2342. done
  2343. if test "${MISSING}" = "" ; then
  2344.     echo You have unpacked all 7 archives.
  2345.     rm -f ark[1-9]isdone
  2346. else
  2347.     echo You still need to unpack the following archives:
  2348.     echo "        " ${MISSING}
  2349. fi
  2350. ##  End of shell archive.
  2351. exit 0
  2352.  
  2353.